﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Reflection;
using System.Globalization;

using Optimization.Utilities;

namespace Optimization.Experiment
{
    internal class Experiment
    {
        static public ISolver Run(ref ExperimentDescriptor ed, int Steps)
        {
            Type solverType = Type.GetType(ed.Solver.Name);
            Type problemType = Type.GetType(ed.Problem.Name);

            Optimization.Utilities.Random.Init(ed.Seed);

            //if seed is -1, save the generated seed
            ed.Seed = Optimization.Utilities.Random.Seed;
            if (ed.Seed == -1)
                Console.WriteLine("Seed is -1");

            Func<ISolver> constructor = ed.Solver.CreateConstructor();
            ISolver solver = constructor();

            solver.DefineProblem(ed.CreateProblemConstructor());

            double solutionValue = double.MaxValue;
            int minSteps = Steps;
            for (int i = 0; i < minSteps; i++)
            {
                solver.Step();
                double nValue = solver.GetSolutionValue();
                if (nValue < solutionValue)
                {
                    solutionValue = nValue;
                    //ed.LastChange = i;
                }
            }

            //ed.SolutionVector = solver.GetSolution().ToString();
            //ed.SolutionValue = solver.GetSolutionValue();

            Solution cSolution = new Solution();
            cSolution.Step = minSteps;
            cSolution.Result = solver.GetSolution().ToArray();
            cSolution.ResultValue = solver.GetSolutionValue();

            if (ExperimentDescriptor.SaveSnapshot)
            {
                IEnumerable<Particle> enumParticle = solver as IEnumerable<Particle>;
                if (enumParticle != null)
                {
                    //ed.Snapshots = enumParticle.Select(p => new ParticleSnapShot(p.Position, p.Value)).ToArray();
                    cSolution.Particles = enumParticle.Select(p => new ParticleXml(p.Value, p.Position.ToArray())).ToArray();
                }
            }

            List<Solution> lSolutions = ed.Solutions.ToList();
            lSolutions.Add(cSolution);
            ed.Solutions = lSolutions.ToArray();

            //if (ed.Solver.Properties == null)
           //     ed.Solver.Properties = ed.PropertiesToArray(solver);

            return solver;
        }

        static public void Continue(ref ExperimentDescriptor ed, ref ISolver solver, int from, int to)
        {
            double solutionValue = solver.GetSolutionValue();
            for (int i = from; i < to; i++)
            {
                solver.Step();
                double nValue = solver.GetSolutionValue();
                if (nValue < solutionValue)
                {
                    solutionValue = nValue;
                    //ed.LastChange = i;
                }
            }

            Solution cSolution = new Solution();
            cSolution.Step = to;

            cSolution.ResultValue = solver.GetSolutionValue();
            cSolution.Result = solver.GetSolution().ToArray();

            if (ExperimentDescriptor.SaveSnapshot)
            {
                IEnumerable<Particle> enumParticle = solver as IEnumerable<Particle>;
                if (enumParticle != null)
                {
                    //cSolution.Particles = enumParticle.Select((p) => (new ParticleXml(p.Value, p.Position))).ToArray();
                    //ed.Snapshots = enumParticle.Select(p => new ParticleSnapShot(p.Position, p.Value)).ToArray();
                    cSolution.Particles = enumParticle.Select(p => new ParticleXml(p.Value, p.Position.ToArray())).ToArray();
                }
            }

            List<Solution> oldSolutions = ed.Solutions.ToList();
            oldSolutions.Add(cSolution);
            ed.Solutions = oldSolutions.ToArray();

            //ed.SolutionVector = solver.GetSolution().ToString();
            //ed.SolutionValue = solver.GetSolutionValue();
        }
    }
}
